#include "uconfig.h"

static const char *module_name[] = {"video input", "video output", "encoder", "scaler", "mosaic", "rtp", "debug"};
static MACRO_STR_T bool_str[] = {
    MACRO_STR(true),
    MACRO_STR(false),
    {-1, NULL}
};
static MACRO_STR_T encoder_mode[] = {
    MACRO_STR(ENCODER_H264),
    MACRO_STR(ENCODER_H265),
    {-1, NULL}
};
static MACRO_STR_T eProfile[] = {
    MACRO_STR(IMVS_PROFILE_AVC),
    MACRO_STR(IMVS_PROFILE_AVC_CAVLC_444),
    MACRO_STR(IMVS_PROFILE_AVC_BASELINE),
    MACRO_STR(IMVS_PROFILE_AVC_MAIN),
    MACRO_STR(IMVS_PROFILE_AVC_EXTENDED),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH10),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH_422),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH_444_PRED),

    MACRO_STR(IMVS_PROFILE_AVC_C_BASELINE),
    MACRO_STR(IMVS_PROFILE_AVC_PROG_HIGH),
    MACRO_STR(IMVS_PROFILE_AVC_C_HIGH),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH10_INTRA),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH_422_INTRA),
    MACRO_STR(IMVS_PROFILE_AVC_HIGH_444_INTRA),

    MACRO_STR(IMVS_PROFILE_HEVC),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN10),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_STILL),
    MACRO_STR(IMVS_PROFILE_HEVC_RExt),

    MACRO_STR(IMVS_PROFILE_HEVC_MONO),
    MACRO_STR(IMVS_PROFILE_HEVC_MONO10),
    MACRO_STR(IMVS_PROFILE_HEVC_MONO12),
    MACRO_STR(IMVS_PROFILE_HEVC_MONO16),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN12),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422_10),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422_12),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_10),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_12),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN10_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN12_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422_10_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_422_12_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_10_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_12_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_16_INTRA),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_STILL),
    MACRO_STR(IMVS_PROFILE_HEVC_MAIN_444_16_STILL),
    {-1, NULL}
};
static MACRO_STR_T entropy_mode[] = {
    MACRO_STR(IMVS_MODE_CAVLC),
    MACRO_STR(IMVS_MODE_CABAC),
    {-1, NULL}
};
static MACRO_STR_T rc_mode[] = {
    MACRO_STR(IMVS_RC_CONST_QP),
    MACRO_STR(IMVS_RC_CBR),
    MACRO_STR(IMVS_RC_VBR),
    MACRO_STR(IMVS_RC_LOW_LATENCY),
    MACRO_STR(IMVS_RC_CAPPED_VBR),
    MACRO_STR(IMVS_RC_BYPASS),
    MACRO_STR(IMVS_RC_PLUGIN),
    MACRO_STR(IMVS_TEST_RC_FILLER),
    {-1, NULL}
};
static MACRO_STR_T gop_mode[] = {
    MACRO_STR(IMVS_GOP_MODE_DEFAULT),
    MACRO_STR(IMVS_GOP_MODE_PYRAMIDAL),
    MACRO_STR(IMVS_GOP_MODE_ADAPTIVE),
    MACRO_STR(IMVS_GOP_MODE_BYPASS),
    MACRO_STR(IMVS_GOP_FLAG_LOW_DELAY),
    MACRO_STR(IMVS_GOP_MODE_LOW_DELAY_P),
    MACRO_STR(IMVS_GOP_MODE_LOW_DELAY_B),
    {-1, NULL}
};
static MACRO_STR_T interlace_mode[] = {
    MACRO_STR(INTERLACE_DISCARD),
    MACRO_STR(INTERLACE_INTERLEAVED),
    {-1, NULL}
};
static MACRO_STR_T mosaic_mode[] = {
    MACRO_STR(IMVS_MOSAIC_4X4),
    MACRO_STR(IMVS_MOSAIC_8X8),
    MACRO_STR(IMVS_MOSAIC_16X16),
    MACRO_STR(IMVS_MOSAIC_32X32),
    MACRO_STR(IMVS_MOSAIC_64X64),
    {-1, NULL}
};
static MACRO_STR_T pixel_format[] = {
    MACRO_STR(IMVS_420_8BITS),
    MACRO_STR(IMVS_422_8BITS),
    MACRO_STR(IMVS_420_10BITS),
    MACRO_STR(IMVS_422_10BITS),
    {-1, NULL}
};

static const char * get_macro_name(MACRO_STR_T* table, int id) 
{ 
    int i = 0; 
    while(table[i].id != -1 && table[i].name != NULL){ 
        if(table[i].id == id) {
            return table[i].name; 
        }
        i++; 
    } 
    return ""; 
} 

static int32_t uconfig_show_global_config(struct uconfig *puconfig)
{
    int i;

    DBG(DBG_INFO, "video input num: %d\n",  puconfig->info.vi_num);
    DBG(DBG_INFO, "video output num: %d\n", puconfig->info.vo_num);
    DBG(DBG_INFO, "encoder num: %d\n",      puconfig->info.encoder_num);
    DBG(DBG_INFO, "scaler num: %d\n",       puconfig->info.scaler_num);
    DBG(DBG_INFO, "mosaic num: %d\n",       puconfig->info.mosaic_num);
    DBG(DBG_INFO, "rtp num: %d\n",          puconfig->info.rtp_num);
    DBG(DBG_INFO, "debug num: %d\n",        puconfig->info.debug_num);

    /*video input parameter*/
    for(i = 0; i < puconfig->info.vi_num; i++){
        input_config_t *vi_cfg;
        vi_cfg = &puconfig->info.input_config[i];

        DBG(DBG_INFO, "video in id: %d\n",          vi_cfg->id);
        DBG(DBG_INFO, "video in buffer num: %d\n",  vi_cfg->nbuffer);
        DBG(DBG_INFO, "video in width: %d\n",       vi_cfg->width);
        DBG(DBG_INFO, "video in height: %d\n",      vi_cfg->height);
        DBG(DBG_INFO, "fps: %d\n",                  vi_cfg->fps);
        DBG(DBG_INFO, "interlace: %s\n",            get_macro_name(interlace_mode, vi_cfg->interlace));
    }
    /*video output parameter*/
    for(i = 0; i < puconfig->info.vo_num; i++){
        output_config_t *vo_cfg;
        vo_cfg = &puconfig->info.output_config[i];

        DBG(DBG_INFO, "video out id: %d\n",         vo_cfg->id);
        DBG(DBG_INFO, "video out buffer num: %d\n", vo_cfg->nbuffer);
        DBG(DBG_INFO, "video out width: %d\n",      vo_cfg->width);
        DBG(DBG_INFO, "video out height: %d\n",     vo_cfg->height);
        DBG(DBG_INFO, "video out fps: %d\n",        vo_cfg->fps);
        DBG(DBG_INFO, "video out enable: %s\n",     get_macro_name(bool_str, vo_cfg->enable));
    }

    /*video scaler parameter*/
    for(i = 0; i < puconfig->info.scaler_num; i++){
        scaler_config_t *scaler_cfg;
        scaler_cfg = &puconfig->info.scaler_config[i];

        DBG(DBG_INFO, "scaler id: %d\n",         scaler_cfg->id);
        DBG(DBG_INFO, "scaler buffer num: %d\n", scaler_cfg->nbuffer);
        DBG(DBG_INFO, "scaler in width: %d\n",   scaler_cfg->in.width);
        DBG(DBG_INFO, "scaler in height: %d\n",  scaler_cfg->in.height);
        DBG(DBG_INFO, "scaler in pixfmt: %s\n",  get_macro_name(pixel_format, scaler_cfg->in.pixfmt));
        DBG(DBG_INFO, "scaler out width: %d\n",  scaler_cfg->out.width);
        DBG(DBG_INFO, "scaler out height: %d\n", scaler_cfg->out.height);
        DBG(DBG_INFO, "scaler out pixfmt: %s\n", get_macro_name(pixel_format, scaler_cfg->out.pixfmt));
    }

    /*video mosaic parameter*/
    for(i = 0; i < puconfig->info.mosaic_num; i++){
        mosaic_config_t *mosaic_cfg;
        mosaic_cfg = &puconfig->info.mosaic_config[i];

        DBG(DBG_INFO, "mosaic id: %d\n",         mosaic_cfg->id);
        DBG(DBG_INFO, "mosaic buffer num: %d\n", mosaic_cfg->nbuffer);
        DBG(DBG_INFO, "mosaic mode: %s\n",       get_macro_name(mosaic_mode, mosaic_cfg->mode));
        DBG(DBG_INFO, "mosaic posx: %d\n",       mosaic_cfg->posx);
        DBG(DBG_INFO, "mosaic posy: %d\n",       mosaic_cfg->posy);
        DBG(DBG_INFO, "mosaic width: %d\n",      mosaic_cfg->width);
        DBG(DBG_INFO, "mosaic height: %d\n",     mosaic_cfg->height);
    }

    /*encoder parameter*/
    for(i = 0; i < puconfig->info.encoder_num; i++){
        encoder_config_t *encoder_cfg;
        encoder_cfg = &puconfig->info.encoder_config[i];

        DBG(DBG_INFO, "encoder id: %d\n",         encoder_cfg->id);
        DBG(DBG_INFO, "encoder buffer num: %d\n", encoder_cfg->nbuffer);
        DBG(DBG_INFO, "encoder enable: %s\n",    get_macro_name(bool_str, encoder_cfg->enable));
        DBG(DBG_INFO, "encoder type: %s\n",      get_macro_name(encoder_mode, encoder_cfg->encoder));
        DBG(DBG_INFO, "encoder width: %d\n",     encoder_cfg->width);
        DBG(DBG_INFO, "encoder height: %d\n",    encoder_cfg->height);
        DBG(DBG_INFO, "encoder bitdepth: %d\n",  encoder_cfg->bitdepth);
        DBG(DBG_INFO, "encoder Level: %d\n",     encoder_cfg->uLevel);
        DBG(DBG_INFO, "encoder profile: %s\n",   get_macro_name(eProfile, encoder_cfg->profile));
        DBG(DBG_INFO, "encoder entropy: %s\n",   get_macro_name(entropy_mode, encoder_cfg->entropymode));
        DBG(DBG_INFO, "encoder numslices: %d\n", encoder_cfg->numslices);
        DBG(DBG_INFO, "encoder slicesize: %d\n", encoder_cfg->slicesize);
        DBG(DBG_INFO, "rc mode: %s\n",           get_macro_name(rc_mode, encoder_cfg->rc.mode));
        DBG(DBG_INFO, "rc cbpsize: %d\n",        encoder_cfg->rc.cbpsize);
        DBG(DBG_INFO, "rc framerate: %d\n",      encoder_cfg->rc.framerate);
        DBG(DBG_INFO, "rc target bitrate: %d\n", encoder_cfg->rc.targetbitrate);
        DBG(DBG_INFO, "rc maxbitrate: %d\n",     encoder_cfg->rc.maxbitrate);
        DBG(DBG_INFO, "rc initialqp: %d\n",      encoder_cfg->rc.initialqp);
        DBG(DBG_INFO, "rc uInitialRemDelay: %d\n",      encoder_cfg->rc.uInitialRemDelay);
        DBG(DBG_INFO, "rc minqp: %d\n",          encoder_cfg->rc.minqp);
        DBG(DBG_INFO, "rc maxqp: %d\n",          encoder_cfg->rc.maxqp);
        DBG(DBG_INFO, "rc uMaxPictureSize: %d\n",encoder_cfg->rc.uMaxPictureSize);
        DBG(DBG_INFO, "rc eOptions: %d\n",       encoder_cfg->rc.eOptions);
        DBG(DBG_INFO, "rc pbdelta: %d\n",        encoder_cfg->rc.ipdelta);
        DBG(DBG_INFO, "rc pbdelta: %d\n",        encoder_cfg->rc.pbdelta);
        DBG(DBG_INFO, "gop mode: %s\n",          get_macro_name(gop_mode, encoder_cfg->gop.mode));
        DBG(DBG_INFO, "gop length: %d\n",        encoder_cfg->gop.length);
        DBG(DBG_INFO, "gop numb: %d\n",          encoder_cfg->gop.numb);
        DBG(DBG_INFO, "gop freqidr: %d\n",       encoder_cfg->gop.freqidr);
    }

    /*rtp parameter*/
    for(i = 0; i < puconfig->info.rtp_num; i++){
        rtp_config_t *rtp_cfg;
        rtp_cfg = &puconfig->info.rtp_config[i];

        DBG(DBG_INFO, "rtp id: %d\n",   rtp_cfg->id);
        DBG(DBG_INFO, "rtp port: %d\n", rtp_cfg->port);
        DBG(DBG_INFO, "rtp ip: %s\n",   rtp_cfg->ipaddr);
    }

    /*debug parameter*/
    for(i = 0; i < puconfig->info.debug_num; i++){
        debug_config_t *debug_cfg;
        debug_cfg = &puconfig->info.debug_config[i];

        DBG(DBG_INFO, "debug id: %d\n",     debug_cfg->id);
        DBG(DBG_INFO, "debug width: %d\n",  debug_cfg->width);
        DBG(DBG_INFO, "debug height: %d\n", debug_cfg->height);
        DBG(DBG_INFO, "debug path: %s\n",   debug_cfg->path);
    }
    
    return 0;
}

static void uconfig_default_param(struct uconfig *puconfig)
{
    int i = 0;
    config_info_t *info = &puconfig->info;
    
    info->vi_num      = 1;
    info->vo_num      = 0;
    info->encoder_num = 1;
    info->scaler_num  = 0;
    info->mosaic_num  = 0;
    info->rtp_num     = 0;
    info->debug_num   = 0;

    for(i = 0; i < info->vi_num; i++){
        input_config_t *vi_cfg;
        vi_cfg = &info->input_config[i];

        vi_cfg->id = i;
        vi_cfg->nbuffer = 5; 
        vi_cfg->width = 1920;
        vi_cfg->height = 1080;
        vi_cfg->fps = 30;
        vi_cfg->interlace = INTERLACE_DISCARD;
    }

    for(i = 0; i < info->vo_num; i++){
        output_config_t *vo_cfg;
        vo_cfg = &info->output_config[i];

        vo_cfg->id = i;
        vo_cfg->nbuffer = 5; 
        vo_cfg->width = 1920;
        vo_cfg->height = 1080;
        vo_cfg->fps = 30;
        vo_cfg->enable = true;
    }
    
    for(i = 0; i < info->scaler_num; i++){
        scaler_config_t *scaler_cfg;
        scaler_cfg = &info->scaler_config[i];

        scaler_cfg->id = i;
        scaler_cfg->nbuffer = 5; 
        scaler_cfg->in.width = 1920;
        scaler_cfg->in.height = 1080;
        scaler_cfg->in.pixfmt = IMVS_422_8BITS;
        scaler_cfg->out.width = 1280;
        scaler_cfg->out.height = 720;
        scaler_cfg->out.pixfmt = IMVS_422_8BITS;
    }

    for(i = 0; i < info->mosaic_num; i++){
        mosaic_config_t *mosaic_cfg;
        mosaic_cfg = &info->mosaic_config[i];

        mosaic_cfg->id = i;
        mosaic_cfg->nbuffer = 5; 
        mosaic_cfg->mode = IMVS_MOSAIC_4X4;
        mosaic_cfg->posx = 0;
        mosaic_cfg->posy = 0;
        mosaic_cfg->width = 128;
        mosaic_cfg->height = 64;
    }

    for(i = 0; i < info->encoder_num; i++){
        encoder_config_t *encoder_cfg;
        encoder_cfg = &info->encoder_config[i];

        encoder_cfg->id = i;
        encoder_cfg->nbuffer = 5; 
        encoder_cfg->enable = true;
        encoder_cfg->encoder = ENCODER_H265;
        encoder_cfg->width = 1920;
        encoder_cfg->height = 1080;
        encoder_cfg->bitdepth = 8;
        encoder_cfg->uLevel = 51;
        encoder_cfg->profile = IMVS_PROFILE_HEVC;
        encoder_cfg->entropymode = 1;
        encoder_cfg->numslices = 1;
        encoder_cfg->slicesize = 0;
        encoder_cfg->rc.mode = 2;
        encoder_cfg->rc.cbpsize = 90000;
        encoder_cfg->rc.framerate = 30;
        encoder_cfg->rc.targetbitrate = 4000000;
        encoder_cfg->rc.maxbitrate = 4000000;
        encoder_cfg->rc.initialqp = 27;
        encoder_cfg->rc.uInitialRemDelay = 90000;
        encoder_cfg->rc.minqp = 10;
        encoder_cfg->rc.maxqp = 52;
        encoder_cfg->rc.uMaxPictureSize = 256000;
        encoder_cfg->rc.eOptions = 8;
        encoder_cfg->rc.ipdelta = 12;
        encoder_cfg->rc.pbdelta = 32;
        encoder_cfg->gop.mode = 2;
        encoder_cfg->gop.length = 30;
        encoder_cfg->gop.numb = 0;
        encoder_cfg->gop.freqidr = 30;
    }
    for(i = 0; i < info->rtp_num; i++){
        rtp_config_t *rtp_cfg;
        rtp_cfg = &info->rtp_config[i];

        rtp_cfg->port = 21510;
        sprintf(rtp_cfg->ipaddr ,"239.100.31.101");
    }

    for(i = 0; i < info->debug_num; i++){
        debug_config_t *debug_cfg;
        debug_cfg = &info->debug_config[i];

        debug_cfg->width = 1920;
        debug_cfg->height = 1080;
        sprintf(debug_cfg->path ,"test%d.yuv", i);
    }
}

static cJSON *uconfig_json_create(void)
{
    cJSON *root, *node;

    root = cJSON_CreateObject();
    if (!root) {
        DBG(DBG_INFO, "Error before: [%s]\n",cJSON_GetErrorPtr());

        return NULL;
    }
    node = cJSON_GetObjectItem(root, "version");
    if(!node){
        node = cJSON_CreateObject();
    }
    if(node){
        CJSON_SET_STRING(root, version,    "1.1");
    }

    return root;
}

static int32_t uconfig_json_save(struct uconfig *puconfig, cJSON *root)
{
    int ret = 0;
    char *buf;
    int cfg_size = 0;

    int fd;
    char *buffer;
    int size = 0x80000;

    buffer = malloc(size);
    if(!buffer){
        return -ENOMEM;
    }

    buf = cJSON_Print(root);
    if(buf){
        cfg_size = strlen(buf);
        memcpy(buffer, buf, cfg_size);
        free(buf);
    }
        
    cJSON_Delete(root);

    if(puconfig->default_config_file){
        fd = open(puconfig->default_config_file, O_CREAT | O_RDWR | O_TRUNC, 0655);
    }else{
        fd = open("config.json", O_CREAT | O_RDWR | O_TRUNC, 0655);
    }
    if(fd > 0){
        ret = write(fd, buffer, cfg_size);
        if(ret < 0){
            printf("write %s error\n", puconfig->default_config_file);
        }
        close(fd);
    }

    free(buffer);
    buffer = NULL;

    return 0;
}

static void uconfig_load_rc_param(cJSON *root, encoder_config_t *encoder)
{
    cJSON *node;

    node = cJSON_GetObjectItem(root, "rc");
    if(!node)
        return;

    CJSON_LOAD_STRING_TO_VALUE(node, mode, encoder->rc.mode, rc_mode);
    CJSON_LOAD_VALUE(node, cbpsize,        encoder->rc.cbpsize);
    CJSON_LOAD_VALUE(node, framerate,      encoder->rc.framerate);
    CJSON_LOAD_VALUE(node, targetbitrate,  encoder->rc.targetbitrate);
    CJSON_LOAD_VALUE(node, maxbitrate,     encoder->rc.maxbitrate);
    CJSON_LOAD_VALUE(node, initialqp,      encoder->rc.initialqp);
    CJSON_LOAD_VALUE(node, uInitialRemDelay,      encoder->rc.uInitialRemDelay);
    CJSON_LOAD_VALUE(node, minqp,          encoder->rc.minqp);
    CJSON_LOAD_VALUE(node, maxqp,          encoder->rc.maxqp);
    CJSON_LOAD_VALUE(node, uMaxPictureSize,encoder->rc.uMaxPictureSize);
    CJSON_LOAD_VALUE(node, eOptions,       encoder->rc.eOptions);
    CJSON_LOAD_VALUE(node, ipdelta,        encoder->rc.ipdelta);
    CJSON_LOAD_VALUE(node, pbdelta,        encoder->rc.pbdelta);
}

static void uconfig_set_rc_param(cJSON *root, encoder_config_t *encoder)
{
    cJSON *node;

    CJSON_CREATE_NODE(root, "rc", node);
    if(!node)
        return;

    CJSON_SET_STRING(node, mode,          get_macro_name(rc_mode, encoder->rc.mode));
    CJSON_SET_VALUE(node, cbpsize,        encoder->rc.cbpsize);
    CJSON_SET_VALUE(node, framerate,      encoder->rc.framerate);
    CJSON_SET_VALUE(node, targetbitrate,  encoder->rc.targetbitrate);
    CJSON_SET_VALUE(node, maxbitrate,     encoder->rc.maxbitrate);
    CJSON_SET_VALUE(node, initialqp,      encoder->rc.initialqp);
    CJSON_SET_VALUE(node, uInitialRemDelay,      encoder->rc.uInitialRemDelay);
    CJSON_SET_VALUE(node, minqp,          encoder->rc.minqp);
    CJSON_SET_VALUE(node, maxqp,          encoder->rc.maxqp);
    CJSON_SET_VALUE(node, uMaxPictureSize,encoder->rc.uMaxPictureSize);
    CJSON_SET_VALUE(node, eOptions,       encoder->rc.eOptions);
    CJSON_SET_VALUE(node, ipdelta,        encoder->rc.ipdelta);
    CJSON_SET_VALUE(node, pbdelta,        encoder->rc.pbdelta);

}

static void uconfig_load_gop_param(cJSON *root, encoder_config_t *encoder)
{
    cJSON *node;

    node = cJSON_GetObjectItem(root, "gop");
    if(!node)
        return;

    CJSON_LOAD_STRING_TO_VALUE(node, mode, encoder->gop.mode, gop_mode);
    CJSON_LOAD_VALUE(node, length,         encoder->gop.length);
    CJSON_LOAD_VALUE(node, numb,           encoder->gop.numb);
    CJSON_LOAD_VALUE(node, freqidr,        encoder->gop.freqidr);
}

static void uconfig_set_gop_param(cJSON *root, encoder_config_t *encoder)
{
    cJSON *node;

    CJSON_CREATE_NODE(root, "gop", node);
    if(!node)
        return;

    CJSON_SET_STRING(node, mode,    get_macro_name(gop_mode, encoder->gop.mode));
    CJSON_SET_VALUE(node, length,   encoder->gop.length);
    CJSON_SET_VALUE(node, numb,     encoder->gop.numb);
    CJSON_SET_VALUE(node, freqidr,  encoder->gop.freqidr);
}

static void uconfig_load_encoder_param(cJSON *root, encoder_config_t *encoder)
{
    CJSON_LOAD_VALUE(root, id,                    encoder->id);
    CJSON_LOAD_VALUE(root, nbuffer,               encoder->nbuffer);
    CJSON_LOAD_STRING_TO_VALUE(root, enable,      encoder->enable, bool_str);
    CJSON_LOAD_STRING_TO_VALUE(root, encoder,     encoder->encoder, encoder_mode);
    CJSON_LOAD_VALUE(root, width,                 encoder->width);
    CJSON_LOAD_VALUE(root, height,                encoder->height);
    CJSON_LOAD_VALUE(root, bitdepth,              encoder->bitdepth);
    CJSON_LOAD_VALUE(root, level,                 encoder->uLevel);
    CJSON_LOAD_STRING_TO_VALUE(root, profile,     encoder->profile, eProfile);
    CJSON_LOAD_STRING_TO_VALUE(root, entropymode, encoder->entropymode, entropy_mode);
    CJSON_LOAD_VALUE(root, numslices,             encoder->numslices);
    CJSON_LOAD_VALUE(root, slicesize,             encoder->slicesize);

    /*rc param load*/
    uconfig_load_rc_param(root, encoder);

    /*gop param load*/
    uconfig_load_gop_param(root, encoder);
}

static void uconfig_set_encoder_param(cJSON *root, encoder_config_t *encoder)
{
    CJSON_SET_VALUE(root, id,           encoder->id);
    CJSON_SET_VALUE(root, nbuffer,      encoder->nbuffer);
    CJSON_SET_STRING(root, enable,      get_macro_name(bool_str, encoder->enable));
    CJSON_SET_STRING(root, encoder,     get_macro_name(encoder_mode, encoder->encoder));
    CJSON_SET_VALUE(root, width,        encoder->width);
    CJSON_SET_VALUE(root, height,       encoder->height);
    CJSON_SET_VALUE(root, bitdepth,     encoder->bitdepth);
    CJSON_SET_VALUE(root, level,        encoder->uLevel);
    // CJSON_SET_STRING(root, profile,     profile_mode[encoder->profile]);
    CJSON_SET_STRING(root, profile,     get_macro_name(eProfile, encoder->profile));
    CJSON_SET_STRING(root, entropymode, get_macro_name(entropy_mode, encoder->entropymode));
    CJSON_SET_VALUE(root, numslices,    encoder->numslices);
    CJSON_SET_VALUE(root, slicesize,    encoder->slicesize);

    /*rc param set*/
    uconfig_set_rc_param(root, encoder);
    /*gop param set*/
    uconfig_set_gop_param(root, encoder);
}

static void uconfig_load_video_in_param(cJSON *root, input_config_t *input)
{
    CJSON_LOAD_VALUE(root, id,                  input->id);
    CJSON_LOAD_VALUE(root, nbuffer,             input->nbuffer);
    CJSON_LOAD_VALUE(root, width,               input->width);
    CJSON_LOAD_VALUE(root, height,              input->height);
    CJSON_LOAD_VALUE(root, fps,                 input->fps);
    CJSON_LOAD_STRING_TO_VALUE(root, interlace, input->interlace, interlace_mode);
}

static void uconfig_set_video_in_param(cJSON *root, input_config_t *input)
{
    CJSON_SET_VALUE(root, id,         input->id);
    CJSON_SET_VALUE(root, nbuffer,    input->nbuffer);
    CJSON_SET_VALUE(root, width,      input->width);
    CJSON_SET_VALUE(root, height,     input->height);
    CJSON_SET_VALUE(root, fps,        input->fps);
    CJSON_SET_STRING(root, interlace, get_macro_name(interlace_mode, input->interlace));
}

static void uconfig_load_video_out_param(cJSON *root, output_config_t *output)
{
    CJSON_LOAD_VALUE(root, id,               output->id);
    CJSON_LOAD_VALUE(root, nbuffer,          output->nbuffer);
    CJSON_LOAD_VALUE(root, width,            output->width);
    CJSON_LOAD_VALUE(root, height,           output->height);
    CJSON_LOAD_VALUE(root, fps,              output->fps);
    CJSON_LOAD_STRING_TO_VALUE(root, enable, output->enable, bool_str);
}

static void uconfig_set_video_out_param(cJSON *root, output_config_t *output)
{
    CJSON_SET_VALUE(root, id,      output->id);
    CJSON_SET_VALUE(root, nbuffer, output->nbuffer);
    CJSON_SET_VALUE(root, width,   output->width);
    CJSON_SET_VALUE(root, height,  output->height);
    CJSON_SET_VALUE(root, fps,     output->fps);
    CJSON_SET_STRING(root, enable, get_macro_name(bool_str, output->enable));
}

static void uconfig_load_scaler_param(cJSON *root, scaler_config_t *scaler)
{
    cJSON *node;

    CJSON_LOAD_VALUE(root, id,      scaler->id);
    CJSON_LOAD_VALUE(root, nbuffer, scaler->nbuffer);

    node = cJSON_GetObjectItem(root, "input");
    if(!node)
        return;

    CJSON_LOAD_VALUE(node, width,                  scaler->in.width);
    CJSON_LOAD_VALUE(node, height,                 scaler->in.height);
    CJSON_LOAD_STRING_TO_VALUE(node, pixel format, scaler->in.pixfmt, pixel_format);

    node = cJSON_GetObjectItem(root, "output");
    if(!node)
        return;

    CJSON_LOAD_VALUE(node, width,                  scaler->out.width);
    CJSON_LOAD_VALUE(node, height,                 scaler->out.height);
    CJSON_LOAD_STRING_TO_VALUE(node, pixel format, scaler->out.pixfmt, pixel_format);
}

static void uconfig_set_scaler_param(cJSON *root, scaler_config_t *scaler)
{
    cJSON *node;

    CJSON_SET_VALUE(root, id,      scaler->id);
    CJSON_SET_VALUE(root, nbuffer, scaler->nbuffer);

    CJSON_CREATE_NODE(root, "input", node);
    if(!node)
        return;

    CJSON_SET_VALUE(node, width,         scaler->in.width);
    CJSON_SET_VALUE(node, height,        scaler->in.height);
    CJSON_SET_STRING(node, pixel format, get_macro_name(pixel_format, scaler->in.pixfmt));

    CJSON_CREATE_NODE(root, "output", node);
    if(!node)
        return;

    CJSON_SET_VALUE(node, width,         scaler->out.width);
    CJSON_SET_VALUE(node, height,        scaler->out.height);
    CJSON_SET_STRING(node, pixel format, get_macro_name(pixel_format, scaler->out.pixfmt));
}

static void uconfig_load_mosaic_param(cJSON *root, mosaic_config_t *mosaic)
{
    CJSON_LOAD_VALUE(root, id,      mosaic->id);
    CJSON_LOAD_VALUE(root, nbuffer, mosaic->nbuffer);
    CJSON_LOAD_STRING_TO_VALUE(root, mode, mosaic->mode, mosaic_mode);
    CJSON_LOAD_VALUE(root, posx,   mosaic->posx);
    CJSON_LOAD_VALUE(root, posy,   mosaic->posy);
    CJSON_LOAD_VALUE(root, width,  mosaic->width);
    CJSON_LOAD_VALUE(root, height, mosaic->height);
}

static void uconfig_set_mosaic_param(cJSON *root, mosaic_config_t *mosaic)
{
    CJSON_SET_VALUE(root, id,      mosaic->id);
    CJSON_SET_VALUE(root, nbuffer, mosaic->nbuffer);
    CJSON_SET_STRING(root, mode,  get_macro_name(mosaic_mode, mosaic->mode));
    CJSON_SET_VALUE(root, posx,   mosaic->posx);
    CJSON_SET_VALUE(root, posy,   mosaic->posy);
    CJSON_SET_VALUE(root, width,  mosaic->width);
    CJSON_SET_VALUE(root, height, mosaic->height);
}

static void uconfig_load_rtp_param(cJSON *root, rtp_config_t *prtp)
{
    cJSON *node;

    CJSON_LOAD_VALUE(root, id,      prtp->id);

    node = cJSON_GetObjectItem(root, "rtp");
    if(!node)
        return;

    CJSON_LOAD_VALUE(node, port,         prtp->port);
    CJSON_LOAD_STRING(node, ipaddr,      prtp->ipaddr);
}

static void uconfig_set_rtp_param(cJSON *root, rtp_config_t *prtp)
{
    cJSON *node;

    CJSON_SET_VALUE(root, id,      prtp->id);

    CJSON_CREATE_NODE(root, "rtp", node);
    if(!node)
        return;

    
    CJSON_SET_VALUE(node, port,     prtp->port);
    CJSON_SET_STRING(node, ipaddr,  prtp->ipaddr);
}

static void uconfig_load_debug_param(cJSON *root, debug_config_t *dcfg)
{
    cJSON *node;
    
    CJSON_LOAD_VALUE(root, id,      dcfg->id);
    node = cJSON_GetObjectItem(root, "debug");
    if(node){
        CJSON_LOAD_VALUE(node, width,    dcfg->width);
        CJSON_LOAD_VALUE(node, height,   dcfg->height);
        CJSON_LOAD_STRING(node, path,    dcfg->path);
    }
}

static void uconfig_set_debug_param(cJSON *root, debug_config_t *dcfg)
{
    cJSON *node;

    CJSON_SET_VALUE(root, id,      dcfg->id);
    CJSON_CREATE_NODE(root, "debug", node);
    if(node){
        CJSON_SET_VALUE(node, width,    dcfg->width);
        CJSON_SET_VALUE(node, height,   dcfg->height);
        CJSON_SET_STRING(node, path,    dcfg->path);
    }
}

static void uconfig_set_param(struct uconfig *puconfig, cJSON *root, uint8_t module)
{
    cJSON *node = NULL;
    cJSON *array = NULL;
    cJSON * item = NULL;
    int i;
    int num;

    CJSON_CREATE_NODE(root, module_name[module], node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return ;
    }
    for(i = 0; i < num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }

        switch(module){
        case 0:{
            uconfig_set_video_in_param(item, &puconfig->info.input_config[i]);
        }break;
        case 1:{
            uconfig_set_video_out_param(item, &puconfig->info.output_config[i]);
        }break;
        case 2:{
            uconfig_set_encoder_param(item, &puconfig->info.encoder_config[i]);
        }break;
        case 3:{
            uconfig_set_scaler_param(item, &puconfig->info.scaler_config[i]);
        }break;
        case 4:{
            uconfig_set_mosaic_param(item, &puconfig->info.mosaic_config[i]);
        }break;
        case 5:{
            uconfig_set_rtp_param(item, &puconfig->info.rtp_config[i]);
        }break;
        case 6:{
            uconfig_set_debug_param(item, &puconfig->info.debug_config[i]);
        }break;
        default:{}break;
        }
    }
}

static int32_t uconfig_load_array(cJSON *root, char *obj, cJSON **array)
{
    cJSON *node;

    node = cJSON_GetObjectItem(root, obj);
    if(!node)
        return 0;

    *array = cJSON_GetObjectItem(node, "channels");
    if(!(*array))
        return 0;

    return cJSON_GetArraySize(*array);
}

static void uconfig_adjust_param(config_info_t *info)
{

}

static int32_t uconfig_load_config_file(struct uconfig *puconfig)
{
    int fd;

    if(!puconfig->input_config_file){
        DBG(DBG_INFO, "No input config file, use default config file\n");
        puconfig->input_config_file = puconfig->default_config_file;
    }

    fd = open(puconfig->input_config_file, O_RDONLY, 0655);
    if(fd > 0){
        char *buffer;
        int size = 0x80000;
        
        buffer = malloc(size);
        if(!buffer){
            return -ENOMEM;
        }
        size = read(fd, buffer, size);

        cJSON *root;
        cJSON *array = NULL;
        uint32_t count = 0;
        int i;

        root = cJSON_Parse(buffer);
        if (!root) {
            DBG(DBG_INFO, "Error before: [%s]\n",cJSON_GetErrorPtr());
            return -EINVAL;
        }

        DBG(DBG_INFO, "vi: [%d] vo: [%d] codec: [%d]\n", puconfig->info.vi_num, puconfig->info.vo_num, puconfig->info.encoder_num);

        CJSON_LOAD_VALUE(root, vi_num,      puconfig->info.vi_num);
        CJSON_LOAD_VALUE(root, vo_num,      puconfig->info.vo_num);
        CJSON_LOAD_VALUE(root, encoder_num, puconfig->info.encoder_num);
        CJSON_LOAD_VALUE(root, scaler_num,  puconfig->info.scaler_num);
        CJSON_LOAD_VALUE(root, mosaic_num,  puconfig->info.mosaic_num);
        CJSON_LOAD_VALUE(root, rtp_num,     puconfig->info.rtp_num);
        CJSON_LOAD_VALUE(root, debug_num,   puconfig->info.debug_num);
        DBG(DBG_INFO, "vi: [%d] vo: [%d] codec: [%d]\n", puconfig->info.vi_num, puconfig->info.vo_num, puconfig->info.encoder_num);
        /*load encode parameter*/
        count = uconfig_load_array(root, "encoder", &array);
        count = (count > MAX_ENCODER_CHANNELS) ? MAX_ENCODER_CHANNELS : count;
        puconfig->info.encoder_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_encoder_param(item, &puconfig->info.encoder_config[i]);
            }
        }
        /*load video input parameter*/
        count = uconfig_load_array(root, "video input", &array);
        count = (count > MAX_VI_CHANNELS) ? MAX_VI_CHANNELS : count;
        puconfig->info.vi_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_video_in_param(item, &puconfig->info.input_config[i]);
            }
        }
        /*load video output parameter*/
        count = uconfig_load_array(root, "video output", &array);
        count = (count > MAX_VO_CHANNELS) ? MAX_VO_CHANNELS : count;
        puconfig->info.vo_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_video_out_param(item, &puconfig->info.output_config[i]);
            }
        }
        /*load scaler parameter*/
        count = uconfig_load_array(root, "scaler", &array);
        count = (count > MAX_SCALER_CHANNELS) ? MAX_SCALER_CHANNELS : count;
        puconfig->info.scaler_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_scaler_param(item, &puconfig->info.scaler_config[i]);
            }
        }
        /*load mosaic parameter*/
        count = uconfig_load_array(root, "mosaic", &array);
        count = (count > MAX_MOSAIC_CHANNELS) ? MAX_MOSAIC_CHANNELS : count;
        puconfig->info.mosaic_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_mosaic_param(item, &puconfig->info.mosaic_config[i]);
            }
        }
        /*load rtp parameter*/
        count = uconfig_load_array(root, "rtp", &array);
        count = (count > MAX_RTP_CHANNELS) ? MAX_RTP_CHANNELS : count;
        puconfig->info.rtp_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_rtp_param(item, &puconfig->info.rtp_config[i]);
            }
        }
        /*load debug parameter*/
        count = uconfig_load_array(root, "debug", &array);
        count = (count > MAX_DEBUG_CHANNELS) ? MAX_DEBUG_CHANNELS : count;
        puconfig->info.debug_num = count;
        for(i = 0; i < count; i++){
            cJSON *item = NULL;
            if(array){
                item = cJSON_GetArrayItem(array, i);
                if(!item)
                    continue;
                uconfig_load_debug_param(item, &puconfig->info.debug_config[i]);
            }
        }
        DBG(DBG_INFO, "vi: [%d] vo: [%d] codec: [%d]\n", puconfig->info.vi_num, puconfig->info.vo_num, puconfig->info.encoder_num);
        //uconfig_adjust_param(puconfig->info);
            
        cJSON_Delete(root);

        close(fd);
        free(buffer);
        buffer = NULL;
    }else{
        DBG(DBG_INFO, "can't open default config file, create default\n");
        uconfig_default_param(puconfig);
    }

    puconfig->op->save(puconfig);

    return 0;
}

static int32_t uconfig_save_config_file(struct uconfig *puconfig)
{
    cJSON *root;
    int32_t ret;
    cJSON *node = NULL;
    cJSON *array = NULL;
    cJSON * item = NULL;
    int i; 

    root = uconfig_json_create();
    if(!root)
        return -ENOMEM;

	CJSON_SET_VALUE(root, vi_num,      puconfig->info.vi_num);
    CJSON_SET_VALUE(root, vo_num,      puconfig->info.vo_num);
    CJSON_SET_VALUE(root, encoder_num, puconfig->info.encoder_num);
    CJSON_SET_VALUE(root, scaler_num,  puconfig->info.scaler_num);
    CJSON_SET_VALUE(root, mosaic_num,  puconfig->info.mosaic_num);
    CJSON_SET_VALUE(root, rtp_num,     puconfig->info.rtp_num);
    CJSON_SET_VALUE(root, debug_num,   puconfig->info.debug_num);

    //uconfig_adjust_param(puconfig->info);
#if 1
    /*set encoder parameter*/
    CJSON_CREATE_NODE(root, "encoder", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.encoder_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_encoder_param(item, &puconfig->info.encoder_config[i]);
    }

    /*set video input parameter*/
    CJSON_CREATE_NODE(root, "video input", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.vi_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_video_in_param(item, &puconfig->info.input_config[i]);
    }

    /*set video output parameter*/
    CJSON_CREATE_NODE(root, "video output", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.vo_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_video_out_param(item, &puconfig->info.output_config[i]);
    }

    /*set scaler parameter*/
    CJSON_CREATE_NODE(root, "scaler", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.scaler_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_scaler_param(item, &puconfig->info.scaler_config[i]);
    }

    /*set mosaic parameter*/
    CJSON_CREATE_NODE(root, "mosaic", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.mosaic_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_mosaic_param(item, &puconfig->info.mosaic_config[i]);
    }

    /*set rtp parameter*/
    CJSON_CREATE_NODE(root, "rtp", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.rtp_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_rtp_param(item, &puconfig->info.rtp_config[i]);
    }

    /*set debug parameter*/
    CJSON_CREATE_NODE(root, "debug", node);
    CJSON_CREATE_ARRAY(node, "channels", array);
    if(!array){
        return -1;
    }
    for(i = 0; i < puconfig->info.debug_num; i++){
        CJSON_CREATE_ARRAY_ITEM(array, i, item);
        if(!item){
            continue;
        }
        uconfig_set_debug_param(item, &puconfig->info.debug_config[i]);
    }
#else
    uconfig_set_param(puconfig, root, 0);
#endif
    ret = uconfig_json_save(puconfig, root);
    if(ret != 0)
        return ret;

    return 0;
}

static int32_t uconfig_start(struct uconfig* puconfig)
{
    int32_t ret = 0;
    return ret;
}

static int32_t uconfig_stop(struct uconfig* puconfig)
{
    int32_t ret = 0;
    return ret;
}

static int32_t uconfig_init(struct uconfig* puconfig)
{
    int32_t ret = 0;

    INIT_LIST_HEAD(&(puconfig->head));
    lock_init(&(puconfig->lock));
    lock_init(&(puconfig->notify_lock));
    wait_init(&(puconfig->wait));

	puconfig->input_config_file = NULL;
    puconfig->default_config_file = "config.json";
    
    return ret;
}

static int32_t uconfig_release(struct uconfig* puconfig)
{
    /*
    free all sources
    ......
    */

    lock_destroy((&puconfig->notify_lock));
    lock_destroy((&puconfig->lock));
    wait_destroy((&puconfig->wait));

    return 0;
}

static int32_t uconfig_register_notify(struct uconfig* puconfig, int32_t event, uconfig_event_notify notify, void* object)
{
    struct uconfig_event_action* paction;
    if(!notify || (event <= UCONFIG_EVENT_NONE) || (event >= UCONFIG_EVENT_MAX)){
        return -EINVAL;
    }
    paction = (struct uconfig_event_action*)malloc(sizeof(struct uconfig_event_action));
    if(!paction){
        DBG(DBG_ERR,"malloc error\n");
        return -ENOMEM;
    }
    paction->notify = notify;
    paction->object = object;
    lock(&(puconfig->notify_lock));
    paction->next = puconfig->paction[event];
    puconfig->paction[event] = paction;
    unlock(&(puconfig->notify_lock));
    return 0;
}

static int32_t uconfig_unregister_notify(struct uconfig* puconfig, int32_t event, void* object)
{
    struct uconfig_event_action *paction,* ptmp;
    if((event <= UCONFIG_EVENT_NONE) || (event >= UCONFIG_EVENT_MAX)){
        return -EINVAL;
    }
    lock(&(puconfig->notify_lock));
    paction = puconfig->paction[event];
    if(paction){
        if(paction->object == object){
            puconfig->paction[event] = paction->next;
            free(paction);
        }else{
            while(paction->next){
                if(paction->next->object == object){
                    ptmp = paction->next;
                    paction->next = ptmp->next;
                    free(ptmp);
                    break;
                }
                paction = paction->next;
            }
        }
    }
    unlock(&(puconfig->notify_lock));

    return 0;
}

static int32_t uconfig_trigger_notify(struct uconfig* puconfig, int32_t event, void* context)
{
    struct uconfig_event_action* paction;
    if((event <= UCONFIG_EVENT_NONE) || (event >= UCONFIG_EVENT_MAX)){
        return -EINVAL;
    }
    lock(&(puconfig->notify_lock));
    paction = puconfig->paction[event];
    while(paction){
        paction->notify(puconfig, event, paction->object, context);
        paction = paction->next;
    }
    unlock(&(puconfig->notify_lock));

    return 0;
}

static struct uconfig_operation uconfig_op =
{
    .init = uconfig_init,
    .release = uconfig_release,
    
    .start = uconfig_start,
    .stop = uconfig_stop,
    
    .show = uconfig_show_global_config,
    .load = uconfig_load_config_file,
    .save = uconfig_save_config_file,

    .register_notify = uconfig_register_notify,
    .unregister_notify = uconfig_unregister_notify,
    .trigger_notify = uconfig_trigger_notify,
};

int32_t create_init_uconfig(struct uconfig** puconfig)
{
    int32_t ret;
    struct uconfig* ptmp;
    (*puconfig) = (struct uconfig*)malloc(sizeof(struct uconfig));
    if(!(*puconfig)){
        DBG(DBG_ERR,"malloc error\n");
        return -ENOMEM;
    }
    ptmp = *puconfig;
    memset(ptmp, 0, sizeof(struct uconfig));
    ptmp->op = &uconfig_op;
    ret = ptmp->op->init(ptmp);
    if(ret < 0){
        DBG(DBG_ERR,"init error\n");
        release_destroy_uconfig(ptmp);
        return ret;
    }
    return 0;
}

void release_destroy_uconfig(struct uconfig* puconfig)
{
    if(puconfig){
        puconfig->op->release(puconfig);
        free(puconfig);
    }
}
        

